import argparse
import json
import os
import logging
import re
import subprocess
import sys

BOOTSTRAP_MAP = {
        "http://192.168.137.75:20029": "ems1",
        "http://192.168.46.177:20029": "ems2",
        "http://192.168.164.96:20029": "ems3",
        "http://192.168.86.7": "ems4",
}


def shell_cmd(cmd, inmsg=None):
    """
    创建子进程执行命令，返回执行结果
    :param cmd: 命令
    :param inmsg: 输入
    :return:
    """
    logging.info("exec cmd -- [%s]", cmd)
    p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    if inmsg:
        p.stdin.write(inmsg)
    out, err = p.communicate()
    logging.info("iret: %s, rs: %s, err: %s", p.returncode, out, err)

    return p.returncode, out, err


def get_repos(repo_ids, arch):
    repos = dict()
    for repo_id in repo_ids:
        cmds = f"/ccb/sbin/cli/ccb select rpm_repos repo_id={repo_id} architecture={arch} -f rpm_repo_path"
        code, cmd_out, error = shell_cmd(cmds)
        if code:
            logging.error(
                f"Failed to get the project repo source,command: {cmds} error: {error}"
            )
            raise ValueError()
        repo = json.loads(cmd_out)
        repos[repo_id] = repo[-1]["_source"]["rpm_repo_path"]
    return repos


def get_emsx(project):
    cmds = f"/ccb/sbin/cli/ccb select projects os_project={project}"
    code, cmd_out, error = shell_cmd(cmds)
    if code:
        logging.error(
            f"Failed to get the project info,command: {cmds} error: {error}"
        )
        raise ValueError()
    repo = json.loads(cmd_out)
    try:
        emsx = repo[-1]["_source"]["emsx"]
    except (KeyError, IndexError):
        emsx = "ems1"

    try:
        bootstrap_repo = repo[-1]["_source"]["bootstrap_rpm_repo"]
        if not bootstrap_repo:
            bootstrap_repo = []
    except (KeyError, IndexError):
        logging.info("bootstrap_rpm_repo not exist")
        bootstrap_repo = []
    logging.info("emsx = %s", emsx)

    return emsx, bootstrap_repo


def get_repo_id(build_id):
    ground_project_repo = {}
    cmds = f"/ccb/sbin/cli/ccb select builds build_id={build_id} -f repo_id,ground_projects"
    logging.info(cmds)
    code, out, error = shell_cmd(cmds)
    if code:
        logging.error(f"Failed to get the repo id,command: {cmds} error: {error}.")
        raise ValueError()
    build = json.loads(out)
    try:
        project_repo = build[0]["_source"]
        project_repo_id = project_repo["repo_id"]
        for ground_project in project_repo["ground_projects"]:
            ground_project_repo_id = ground_project["repo_id"]
            ground_project_emsx = ground_project["emsx"]
            ground_project_repo[ground_project_repo_id] = ground_project_emsx
    except (KeyError, IndexError):
        raise ValueError()
    return project_repo_id, ground_project_repo


def get_bootstrap_repo(ebs_server, bootstrap_repo, arch):
    repo_content = ""
    for repos in bootstrap_repo:
        repo_url = repos.get("repo")
        ebs_server = f"{ebs_server}/api"
        ip_port_result = re.match("http://192.168.\d+.\d+:\d+", repo_url)
        if ip_port_result:
            ip_port = ip_port_result.group(0)
            bootstrap_emsx = BOOTSTRAP_MAP.get(ip_port)
            repo_url = repo_url.replace(ip_port, f"{ebs_server}/{bootstrap_emsx}")
        repo_content += f"""
[bootstrap_{repos.get("name")}]
name=bootstrap_{repos.get("name")}
baseurl={repo_url}/{arch}
enabled=1
gpgcheck=0
"""
    return repo_content


def update_repo(repo_path, ebs_server, build_id, os_project, arch):
    """
    Generate the repo source
    :param branch: Warehouse branch
    """
    repo_ids = []
    try:
        project_repo_id, ground_project_repo_id = get_repo_id(build_id)
        repo_ids.append(project_repo_id)
        repo_ids.extend(ground_project_repo_id.keys())
        repos = get_repos(repo_ids, arch)
        logging.info("ground_project_repo_id = %s", ground_project_repo_id)
    except (ValueError, IndexError, KeyError) as ebs_error:
        logging.error(ebs_error)
        return False

    repo_content = ""
    emsx, bootstrap_repo = get_emsx(os_project)
    for project, repo in repos.items():
        emsx = ground_project_repo_id.get(project, emsx)
        repo_content += f"""
[{project}]
name={project}
baseurl={ebs_server}/api/{emsx}{repo}
enabled=1
gpgcheck=0
"""
    bootstrap_repo_content = get_bootstrap_repo(ebs_server, bootstrap_repo, arch)
    repo_content += bootstrap_repo_content

    try:
        with open(
                os.path.join(repo_path, "ci-tools.repo"), "w", encoding="utf-8"
        ) as file:
            file.write(repo_content)
        logging.info(repo_content)
        return True
    except IOError as error:
        logging.error(error)
        return False


def init_args():
    """
    init args
    :return:
    """
    parser = argparse.ArgumentParser()
    parser.add_argument("-d", type=str, dest="repo_path", help="repo path")
    parser.add_argument("-e", type=str, dest="ebs_server", help="ebs_server")
    parser.add_argument("-b", type=str, dest="build_id", help="build_id")
    parser.add_argument("-p", type=str, dest="os_project", help="os_project")
    parser.add_argument("-a", type=str, dest="arch", help="arch")
    return parser.parse_args()


if "__main__" == __name__:
    args = init_args()
    update_repo(args.repo_path, args.ebs_server, args.build_id, args.os_project, args.arch)
